#include "VulkanWindow.h"

CVulkanWindow::CVulkanWindow(vk::SurfaceKHR InVKSurface)
{
    VKSurface = InVKSurface;

    //make sure surface format is supported
    {
        bool bSurfaceFormatSupported = false;
        auto SurfaceFormats = CVulkanContext::Get()->GetPhysicalDevice().getSurfaceFormatsKHR(VKSurface);
        if (SurfaceFormats.size() == 0)
        {
            assert(false && "Surface format is not supported!");
        }

        for(auto SurfaceFormat:SurfaceFormats)
        {
            if(SurfaceFormat.format==CVulkanContext::Get()->GetSwapChainImageFormat())
            {
                bSurfaceFormatSupported=true;
                break;
            }
        }

        assert(bSurfaceFormatSupported && "Surface format is not supported!");
    }

    // get present mode
    {
        auto PresentModes=CVulkanContext::Get()->GetPhysicalDevice().getSurfacePresentModesKHR(VKSurface);
        SurfacePresentMode=PresentModes[0];
    }


}

CVulkanWindow::~CVulkanWindow()
{
    //make sure any thing (command buffer and descriptor) is safe to destory
    if(RenderFence)
    {
        CVulkanContext::Get()->GetRecycleObjects()->Fences.Add(RenderFence);
    }

    //TODO recycle any thing
}

vk::SurfaceKHR CVulkanWindow::GetVKSurface()
{
    return VKSurface;
}

uint8_t CVulkanWindow::GetSwapChainImageCount()
{
    return SwapChainImageCount;
}

vk::CommandBuffer CVulkanWindow::GetPrimaryCommandBuffer()
{
    return PrimaryCommandBuffer;
}

vk::Framebuffer CVulkanWindow::GetCurrentFrameBuffer()
{
    return  FrameBuffers[CurrentFrame];
}

vk::Extent2D CVulkanWindow::GetSwapChainImageSize()
{
    return SwapChainImageSize;
}

vk::Image CVulkanWindow::GetCurrentSwapChainImage()
{
    return SwapchainImage[CurrentFrame];
}

void CVulkanWindow::UpdateSwapChain()
{
    vk::SwapchainKHR OldSwapchain = VKSwapChain;

    // get capability
    VkSurfaceCapabilitiesKHR SurfaceCapabilities_C;
    VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(CVulkanContext::Get()->GetPhysicalDevice(), VKSurface, &SurfaceCapabilities_C);
    if(result == VK_ERROR_SURFACE_LOST_KHR)
    {
        //window might be closed in window task bar
        bNeedRebuildSwapChain=true;
        return;
    }
    assert(result == VK_SUCCESS && "Failed to get surface capabilities!");
    vk::SurfaceCapabilitiesKHR SurfaceCapabilities(SurfaceCapabilities_C);

    SwapChainImageSize=SurfaceCapabilities.currentExtent;

    if(SwapChainImageSize.width==0 || SwapChainImageSize.height==0)
    {
        bNeedRebuildSwapChain=true;
        return;
    }

    // get prethansform
    vk::SurfaceTransformFlagBitsKHR preTransform;
    if (SurfaceCapabilities.supportedTransforms & vk::SurfaceTransformFlagBitsKHR::eIdentity) {
        preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
    } else {
        preTransform = SurfaceCapabilities.currentTransform;
    }

    // Find a supported composite alpha mode - one of these is guaranteed to be set
    vk::CompositeAlphaFlagBitsKHR compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
    
    {
        TVector<vk::CompositeAlphaFlagBitsKHR> CompositeAlphaFlags= {
            vk::CompositeAlphaFlagBitsKHR::eOpaque,
            vk::CompositeAlphaFlagBitsKHR::ePreMultiplied,
            vk::CompositeAlphaFlagBitsKHR::ePostMultiplied,
            vk::CompositeAlphaFlagBitsKHR::eInherit,
        };
        for (uint32_t i = 0; i < CompositeAlphaFlags.size(); i++) {
            if (SurfaceCapabilities.supportedCompositeAlpha & CompositeAlphaFlags[i]) {
                compositeAlpha = CompositeAlphaFlags[i];
                break;
            }
        }
    }

    uint32_t MinSwapchainImageNum=CMathBase::Max((uint32_t)2,SurfaceCapabilities.minImageCount);

    if(SurfaceCapabilities.maxImageCount>0 && MinSwapchainImageNum>SurfaceCapabilities.maxImageCount)
    {
        MinSwapchainImageNum=SurfaceCapabilities.maxImageCount;
    }


    //getSurfaceSupportKHR() must called onece per surface, it is NOT a check function 
    if(CVulkanContext::Get()->GetPhysicalDevice().getSurfaceSupportKHR(CVulkanContext::Get()->GetQueueFamilyIndex(),VKSurface)!=VK_TRUE)
    {
        assert(false&&"surface is not supported!");
    }

    vk::SwapchainCreateInfoKHR SwapchainInfo=vk::SwapchainCreateInfoKHR()
            .setOldSwapchain(OldSwapchain)
            .setSurface(VKSurface)
            .setMinImageCount(MinSwapchainImageNum)
            .setImageFormat(CVulkanContext::Get()->GetSwapChainImageFormat())
            .setImageExtent(SwapChainImageSize)
            .setPreTransform(preTransform)
            .setImageColorSpace(vk::ColorSpaceKHR::eSrgbNonlinear)
            .setImageArrayLayers(1)
            .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment)
            .setImageSharingMode(vk::SharingMode::eExclusive)
            .setCompositeAlpha(compositeAlpha)
            .setClipped(true);
            
    VKSwapChain =CVulkanContext::Get()->GetDevice().createSwapchainKHR(SwapchainInfo);

    SwapChainImageCount=CVulkanContext::Get()->GetDevice().getSwapchainImagesKHR(VKSwapChain).size();
    if(OldSwapchain)
    {
        CVulkanContext::Get()->GetDevice().destroySwapchainKHR(OldSwapchain, nullptr);
    }

}


void CVulkanWindow::UpdateSwapchainImageAndImageViews()
{
    //destory image views before create
    for(auto& SwapchainImageView : SwapchainImageViews)
    {
        CVulkanContext::Get()->GetDevice().destroyImageView(SwapchainImageView,nullptr);
    }

    SwapchainImage=CVulkanContext::Get()->GetDevice().getSwapchainImagesKHR(VKSwapChain);

    SwapchainImageViews={};// clear first
    for(auto Image:SwapchainImage)
    {     
        auto ImageViewInfo=vk::ImageViewCreateInfo()
            .setImage(Image)
            .setViewType(vk::ImageViewType::e2D)
            .setFormat(CVulkanContext::Get()->GetSwapChainImageFormat())
            .setSubresourceRange(
                vk::ImageSubresourceRange(vk::ImageAspectFlags(vk::ImageAspectFlagBits::eColor),0,1,0,1));
            
        SwapchainImageViews.Add(CVulkanContext::Get()->GetDevice().createImageView(ImageViewInfo));
    }

}

void CVulkanWindow::UpdateDepthImageAndImageView()
{
    //destroy before create
    if(DepthImage)
    {
        CVulkanContext::Get()->GetDevice().destroyImageView(DepthView, nullptr);
        CVulkanContext::Get()->GetDevice().destroyImage(DepthImage, nullptr);
        CVulkanContext::Get()->GetDevice().freeMemory(DepthMemory, nullptr);
    }

    auto ImageInfo=vk::ImageCreateInfo()
    .setImageType(vk::ImageType::e2D)
    .setFormat(CVulkanContext::Get()->GetWidgetDepthImageFormat())
    .setExtent({(uint32_t)SwapChainImageSize.width,(uint32_t)SwapChainImageSize.height,1})
    .setMipLevels(1)
    .setArrayLayers(1)
    .setUsage(vk::ImageUsageFlagBits::eDepthStencilAttachment);

    DepthImage=CVulkanContext::Get()->GetDevice().createImage(ImageInfo);

    vk::MemoryRequirements MemRequire=CVulkanContext::Get()->GetDevice().getImageMemoryRequirements(DepthImage);
    auto MemoryTypeIndex=CVulkanContext::Get()->GetMemoryTypeIndex(MemRequire,vk::MemoryPropertyFlagBits::eDeviceLocal);

    auto AllocateInfo =vk::MemoryAllocateInfo()
        .setAllocationSize(MemRequire.size)
        .setMemoryTypeIndex(MemoryTypeIndex);

    DepthMemory=CVulkanContext::Get()->GetDevice().allocateMemory(AllocateInfo);

    CVulkanContext::Get()->GetDevice().bindImageMemory(DepthImage,DepthMemory,0);

    vk::ImageViewCreateInfo ImageViewInfo=vk::ImageViewCreateInfo()
        .setImage(DepthImage)
        .setViewType(vk::ImageViewType::e2D)
        .setFormat(CVulkanContext::Get()->GetWidgetDepthImageFormat())
        .setSubresourceRange(vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1));

    DepthView=CVulkanContext::Get()->GetDevice().createImageView(ImageViewInfo);    
}

void CVulkanWindow::UpdateClearRenderPass()
{
    //destroy before create
    if(ClearRenderPass)
    {
        CVulkanContext::Get()->GetDevice().destroyRenderPass(ClearRenderPass,nullptr);
    }

    TVector<vk::AttachmentDescription> Attachments=
    {
        vk::AttachmentDescription()
            .setFormat(CVulkanContext::Get()->GetSwapChainImageFormat())
            .setSamples(vk::SampleCountFlagBits::e1)
            .setLoadOp(vk::AttachmentLoadOp::eClear)
            .setStoreOp(vk::AttachmentStoreOp::eStore)
            .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
            .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
            .setInitialLayout(vk::ImageLayout::eUndefined)
            .setFinalLayout(vk::ImageLayout::eColorAttachmentOptimal)
        ,        

        vk::AttachmentDescription()
            .setFormat(CVulkanContext::Get()->GetWidgetDepthImageFormat())
            .setSamples(vk::SampleCountFlagBits::e1)
            .setLoadOp(vk::AttachmentLoadOp::eClear)
            .setStoreOp(vk::AttachmentStoreOp::eStore)
            .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
            .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
            .setInitialLayout(vk::ImageLayout::eUndefined)
            .setFinalLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal)
    };

    auto ColorAttachmentRef=vk::AttachmentReference()
        .setAttachment(0)
        .setLayout(vk::ImageLayout::eColorAttachmentOptimal);

    auto DepthAttachmentRef=vk::AttachmentReference()
        .setAttachment(1)
        .setLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);

    auto Subpass=vk::SubpassDescription()
        .setPipelineBindPoint(vk::PipelineBindPoint::eGraphics)
        .setColorAttachmentCount(1)
        .setPColorAttachments(&ColorAttachmentRef)
        .setPDepthStencilAttachment(&DepthAttachmentRef);
    
    TVector<vk::SubpassDependency> SubpassDependencise={
        vk::SubpassDependency()
        .setSrcSubpass(VK_SUBPASS_EXTERNAL)
        .setDstSubpass(0)
        .setSrcStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
        .setDstStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
        .setSrcAccessMask(vk::AccessFlagBits::eNone)
        .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite)
        ,

        vk::SubpassDependency()
        .setSrcSubpass(0)
        .setDstSubpass(VK_SUBPASS_EXTERNAL)
        .setSrcStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
        .setDstStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
        .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite)
        .setDstAccessMask(vk::AccessFlagBits::eNone)
    
    };
    
    auto RenderPassInfo=vk::RenderPassCreateInfo()
        .setAttachmentCount(Attachments.size())
        .setPAttachments(Attachments.data())
        .setSubpassCount(1)
        .setPSubpasses(&Subpass)
        .setDependencies(SubpassDependencise);

    ClearRenderPass=CVulkanContext::Get()->GetDevice().createRenderPass(RenderPassInfo);

}

void CVulkanWindow::UpdatePresentRenderPass()
{
    //destroy before create
    if(PresentRenderPass)
    {
        CVulkanContext::Get()->GetDevice().destroyRenderPass(PresentRenderPass,nullptr);
    }

    TVector<vk::AttachmentDescription> Attachments=
    {
        vk::AttachmentDescription()
            .setFormat(CVulkanContext::Get()->GetSwapChainImageFormat())
            .setSamples(vk::SampleCountFlagBits::e1)
            .setLoadOp(vk::AttachmentLoadOp::eLoad)
            .setStoreOp(vk::AttachmentStoreOp::eStore)
            .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
            .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
            .setInitialLayout(vk::ImageLayout::eColorAttachmentOptimal)
            .setFinalLayout(vk::ImageLayout::ePresentSrcKHR)
    };

    auto ColorAttachmentRef=vk::AttachmentReference()
        .setAttachment(0)
        .setLayout(vk::ImageLayout::eColorAttachmentOptimal);

    auto Subpass=vk::SubpassDescription()
        .setPipelineBindPoint(vk::PipelineBindPoint::eGraphics)
        .setColorAttachmentCount(1)
        .setPColorAttachments(&ColorAttachmentRef);
    
    auto SubpassDependency=vk::SubpassDependency()
        .setSrcSubpass(VK_SUBPASS_EXTERNAL)
        .setDstSubpass(0)
        .setSrcStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
        .setDstStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
        .setSrcAccessMask(vk::AccessFlagBits::eNone)
        .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite);
    
    auto RenderPassInfo=vk::RenderPassCreateInfo()
        .setAttachmentCount(Attachments.size())
        .setPAttachments(Attachments.data())
        .setSubpassCount(1)
        .setPSubpasses(&Subpass)
        .setDependencyCount(1)
        .setPDependencies(&SubpassDependency);

    PresentRenderPass=CVulkanContext::Get()->GetDevice().createRenderPass(RenderPassInfo);

}

void CVulkanWindow::UpdatePresentFrameBuffers()
{
    //destroy before create
    for(auto& FrameBuffer : PresentFrameBuffers)
    {
        CVulkanContext::Get()->GetDevice().destroyFramebuffer(FrameBuffer,nullptr);
    }

    PresentFrameBuffers={};

    for(int i=0;i<SwapchainImageViews.size();i++)
    {
        TVector<vk::ImageView> Attachments={SwapchainImageViews[i]};

        auto FrameBufferInfo=vk::FramebufferCreateInfo()
            .setRenderPass(PresentRenderPass)
            .setAttachmentCount(1)
            .setPAttachments(Attachments.Data())
            .setWidth(SwapChainImageSize.width)
            .setHeight(SwapChainImageSize.height)
            .setLayers(1);

        PresentFrameBuffers.Add(CVulkanContext::Get()->GetDevice().createFramebuffer(FrameBufferInfo));
    }
}

void CVulkanWindow::UpdateFrameBuffers()
{
    //destroy before create
    for(auto& FrameBuffer : FrameBuffers)
    {
        CVulkanContext::Get()->GetDevice().destroyFramebuffer(FrameBuffer,nullptr);
    }

    FrameBuffers={};

    for(int i=0;i<SwapchainImageViews.size();i++)
    {
        TVector<vk::ImageView> Attachments={
            SwapchainImageViews[i],
            DepthView
        };

        auto FrameBufferInfo=vk::FramebufferCreateInfo()
            .setRenderPass(ClearRenderPass)
            .setAttachmentCount(2)
            .setPAttachments(Attachments.Data())
            .setWidth(SwapChainImageSize.width)
            .setHeight(SwapChainImageSize.height)
            .setLayers(1);

        FrameBuffers.Add(CVulkanContext::Get()->GetDevice().createFramebuffer(FrameBufferInfo));
    }


}

void CVulkanWindow::UpdateRenderSemaphores()
{
    //destroy before create
    if(ImageAvailableSemaphore)
    {
       CVulkanContext::Get()->GetDevice().destroySemaphore(ImageAvailableSemaphore,nullptr);
    }

    if(PresentWaitSemaphore)
    {
        CVulkanContext::Get()->GetDevice().destroySemaphore(PresentWaitSemaphore,nullptr);
    }


    ImageAvailableSemaphore=CVulkanContext::Get()->GetDevice().createSemaphore(vk::SemaphoreCreateInfo());
    PresentWaitSemaphore=CVulkanContext::Get()->GetDevice().createSemaphore(vk::SemaphoreCreateInfo());
    


}

void CVulkanWindow::UpdateFence()
{
    //destroy before create

    CVulkanContext::Get()->GetDevice().destroyFence(RenderFence,nullptr);
    
    RenderFence = CVulkanContext::Get()->GetDevice().createFence(vk::FenceCreateInfo(vk::FenceCreateFlagBits::eSignaled));

    bNeedWaitFormerFrame=true;
}

// void CVulkanWindow::UpdateFence()
// {
//     //destroy before create
//     // for(auto& Fence : ImageFences)
//     // {
//     //     CVulkanContext::Get()->GetDevice().destroyFence(Fence,nullptr);
//     // }

//     // ImageFences.Clear();

//     // for(int i=0;i<SwapchainImageViews.size();i++)
//     // {
//     //     ImageFences.Add(CVulkanContext::Get()->GetDevice().createFence(vk::FenceCreateInfo(vk::FenceCreateFlagBits::eSignaled)));
//     // }

// }

void CVulkanWindow::OnSwapChainResized()
{
    UpdateSwapchainImageAndImageViews();
    UpdateDepthImageAndImageView();
    UpdateClearRenderPass();
    UpdatePresentRenderPass();
    UpdatePresentFrameBuffers();
    UpdateFrameBuffers();
    UpdateRenderSemaphores();
    UpdateFence(); 

}

void CVulkanWindow::PrepareFrame()
{
    //initialize surface
    if(!PrimaryCommandBuffer)
    {
        //allocate clear image command buffer
        {
            vk::CommandBufferAllocateInfo CommandBufferAllocateInfo=vk::CommandBufferAllocateInfo()
            .setCommandPool(CVulkanContext::Get()->GetRenderThreadCommandPool())
            .setLevel(vk::CommandBufferLevel::ePrimary)
            .setCommandBufferCount(1);

            ClearImageBuffer=CVulkanContext::Get()->GetDevice().allocateCommandBuffers(CommandBufferAllocateInfo)[0];

        }

        //allocate Primary command buffer
        {
            vk::CommandBufferAllocateInfo CommandBufferAllocateInfo=vk::CommandBufferAllocateInfo()
            .setCommandPool(CVulkanContext::Get()->GetRenderThreadCommandPool())
            .setLevel(vk::CommandBufferLevel::ePrimary)
            .setCommandBufferCount(1);

            PrimaryCommandBuffer=CVulkanContext::Get()->GetDevice().allocateCommandBuffers(CommandBufferAllocateInfo)[0];

        }

        UpdateSwapChain();
        if(bNeedRebuildSwapChain)
        {
            return;
        }
        UpdateSwapchainImageAndImageViews();
        UpdateDepthImageAndImageView();
        UpdateClearRenderPass();
        UpdatePresentRenderPass();
        UpdatePresentFrameBuffers();
        UpdateFrameBuffers();
        UpdateRenderSemaphores();
        UpdateFence();
    }



    if(bNeedRebuildSwapChain)
    {
        bNeedRebuildSwapChain=false;
        CVulkanContext::Get()->GetDevice().waitIdle();
        UpdateSwapChain();
        if(bNeedRebuildSwapChain)
        {
            //cant rebuild swap chain, just return and wait next frame
            return;
        }
        OnSwapChainResized();
    }



    
    // vk::Result WaitResult=CVulkanContext::Get()->GetDevice().waitForFences(ImageFences[CurrentFrame],true,UINT64_MAX);
    // assert(WaitResult==vk::Result::eSuccess);
    
    // CVulkanContext::Get()->GetDevice().resetFences(ImageFences[CurrentFrame]);

}

void CVulkanWindow::WaitFormerFrame()
{
    if(bNeedRebuildSwapChain)
    {
        return;
    }

    //wait render fence
    if(bNeedWaitFormerFrame)
    {

        vk::Result WaitResult=CVulkanContext::Get()->GetDevice().waitForFences({RenderFence},true,1000000000);
        if(WaitResult==vk::Result::eSuccess)
        {
            //reset fence
            CVulkanContext::Get()->GetDevice().resetFences({RenderFence});
            
        }
        else
        {
            assert(false && "wait fence failed!");
        }

        if(bNeedRequireImage)
        {
            auto AcquireResult=CVulkanContext::Get()->GetDevice().acquireNextImageKHR(
                VKSwapChain
                ,UINT64_MAX
                ,ImageAvailableSemaphore
                ,nullptr
            );

            if(AcquireResult.result==vk::Result::eErrorOutOfDateKHR || AcquireResult.result==vk::Result::eSuboptimalKHR)
            {
                //unsignal the semaphore
                

                bNeedRebuildSwapChain=true;
               
            }
            else
            {
                assert(AcquireResult.result==vk::Result::eSuccess);

                CurrentFrame=AcquireResult.value;

                bNeedRequireImage=false;
            }
        }

    }

}

void CVulkanWindow::PrepareRecord(const SPreRenderWidgets& AllVulkanWidgets)
{
    if(bNeedRebuildSwapChain)
    {
        return;
    }

    RectPainter[CVulkanContext::Get()->CurrentBufferIndex].PreProcess(AllVulkanWidgets.RectWidgets);
    CirclePainter[CVulkanContext::Get()->CurrentBufferIndex].PreProcess(AllVulkanWidgets.CircleWidgets);
    RingPainter[CVulkanContext::Get()->CurrentBufferIndex].PreProcess(AllVulkanWidgets.RingWidgets);
    ImagePainter[CVulkanContext::Get()->CurrentBufferIndex].PreProcess(AllVulkanWidgets.ImageWidgets);
    TextPainter[CVulkanContext::Get()->CurrentBufferIndex].PreProcess(AllVulkanWidgets.TextWidgets);
    StaticTextPainter[CVulkanContext::Get()->CurrentBufferIndex].PreProcess(AllVulkanWidgets.StaticTextWidgets);
    LinePainter[CVulkanContext::Get()->CurrentBufferIndex].PreProcess(AllVulkanWidgets.LineWidgets);
    TrianglePainter[CVulkanContext::Get()->CurrentBufferIndex].PreProcess(AllVulkanWidgets.TriangleWidgets);
    ViewportPainter[CVulkanContext::Get()->CurrentBufferIndex].PreProcess(AllVulkanWidgets.ViewportWidgets);
}

void CVulkanWindow::CreateRecordTasks()
{
    SecondaryCommandBuffers.Clear();
    
    if(bNeedRebuildSwapChain)
    {
        return;
    }

    RectPainter[CVulkanContext::Get()->CurrentBufferIndex].CreateSelfRecordTasks(this,SecondaryCommandBuffers);
    CirclePainter[CVulkanContext::Get()->CurrentBufferIndex].CreateSelfRecordTasks(this,SecondaryCommandBuffers);
    RingPainter[CVulkanContext::Get()->CurrentBufferIndex].CreateSelfRecordTasks(this,SecondaryCommandBuffers);
    ImagePainter[CVulkanContext::Get()->CurrentBufferIndex].CreateSelfRecordTasks(this,SecondaryCommandBuffers);
    TextPainter[CVulkanContext::Get()->CurrentBufferIndex].CreateSelfRecordTasks(this,SecondaryCommandBuffers);
    StaticTextPainter[CVulkanContext::Get()->CurrentBufferIndex].CreateSelfRecordTasks(this,SecondaryCommandBuffers);
    LinePainter[CVulkanContext::Get()->CurrentBufferIndex].CreateSelfRecordTasks(this,SecondaryCommandBuffers);
    TrianglePainter[CVulkanContext::Get()->CurrentBufferIndex].CreateSelfRecordTasks(this,SecondaryCommandBuffers);
    ViewportPainter[CVulkanContext::Get()->CurrentBufferIndex].CreateSelfRecordTasks(this,SecondaryCommandBuffers);
}

void CVulkanWindow::RecordPrimaryCommandBuffer()
{
    if(SecondaryCommandBuffers.Empty())
    {
        return;
    }

    vk::ClearValue ClearValues[2];
    ClearValues[0].color.float32[0]=0.2f;
    ClearValues[0].color.float32[1]=0.2f;
    ClearValues[0].color.float32[2]=0.2f;
    ClearValues[0].color.float32[3]=1.0f;

    ClearValues[1].depthStencil.depth=1.0f;
    ClearValues[1].depthStencil.stencil=0;

    //clear Image 
    {     
        auto ClearImageBeginInfo=vk::CommandBufferBeginInfo()
            .setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);

        ClearImageBuffer.begin(ClearImageBeginInfo);


        auto ClearRenderPassBeginInfo=vk::RenderPassBeginInfo()
            .setRenderPass(ClearRenderPass)
            .setFramebuffer(FrameBuffers[CurrentFrame])
            .setRenderArea(vk::Rect2D(vk::Offset2D(0,0),SwapChainImageSize))
            .setClearValueCount(2)
            .setPClearValues(ClearValues);

        ClearImageBuffer.beginRenderPass(ClearRenderPassBeginInfo,vk::SubpassContents::eInline);
        ClearImageBuffer.endRenderPass();
    
        ClearImageBuffer.end();
    }



    auto BeginInfo=vk::CommandBufferBeginInfo()
        .setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);

    PrimaryCommandBuffer.begin(BeginInfo);




    //start render the widget
    if(!SecondaryCommandBuffers.Empty())
    {   
        auto RenderPassBeginInfo=vk::RenderPassBeginInfo()
            .setRenderPass(CVulkanContext::Get()->GetWidgetRenderPass())
            .setFramebuffer(FrameBuffers[CurrentFrame])
            .setRenderArea(vk::Rect2D(vk::Offset2D(0,0),SwapChainImageSize))
            .setClearValueCount(2)
            .setPClearValues(ClearValues);

        PrimaryCommandBuffer.beginRenderPass(RenderPassBeginInfo,vk::SubpassContents::eSecondaryCommandBuffers);

        //render rect widget
        if(!SecondaryCommandBuffers.RectWidgetRenderPassCommandBuffers.Empty())
        {
            PrimaryCommandBuffer.executeCommands(SecondaryCommandBuffers.RectWidgetRenderPassCommandBuffers);
        }

        //render imgae widget
        if(!SecondaryCommandBuffers.ImageWidgetRenderPassCommandBuffers.Empty())
        {
            PrimaryCommandBuffer.executeCommands(SecondaryCommandBuffers.ImageWidgetRenderPassCommandBuffers);
        }
        //render text widget
        if(!SecondaryCommandBuffers.TextImageWidgetRenderPassCommandBuffers.Empty())
        {
            PrimaryCommandBuffer.executeCommands(SecondaryCommandBuffers.TextImageWidgetRenderPassCommandBuffers);
        }
        //render canvas widget
        if(!SecondaryCommandBuffers.CanvasWidgetRenderPassCommandBuffers.Empty())
        {
            PrimaryCommandBuffer.executeCommands(SecondaryCommandBuffers.CanvasWidgetRenderPassCommandBuffers);
        }


        PrimaryCommandBuffer.endRenderPass();
    }


    //use present render pass to prepare the image layout
    {
        auto PresentRenderPassBeginInfo=vk::RenderPassBeginInfo()
            .setRenderPass(PresentRenderPass)
            .setFramebuffer(PresentFrameBuffers[CurrentFrame])
            .setRenderArea(vk::Rect2D(vk::Offset2D(0,0),SwapChainImageSize))
            .setClearValueCount(2)
            .setPClearValues(ClearValues);

        PrimaryCommandBuffer.beginRenderPass(PresentRenderPassBeginInfo,vk::SubpassContents::eInline);

        PrimaryCommandBuffer.endRenderPass();
    }


    PrimaryCommandBuffer.end();

}

bool CVulkanWindow::RecordNothing()
{
    return SecondaryCommandBuffers.Empty();
}

// void CVulkanWindow::CollectSubmitFences(TVector<vk::Fence>& OutFences)
// {
//     OutFences.Add(RenderFence);
// }

// void CVulkanWindow::CollectSubmitWaitSemaphores(TVector<vk::Semaphore> &OutWaitSemaphores)
// {
//     OutWaitSemaphores.Add(ImageAvailableSemaphore);
// }

// void CVulkanWindow::CollectDrawCompleteSemaphores(TVector<vk::Semaphore> &OutDrawCompleteSemaphores)
// {
//     OutDrawCompleteSemaphores.Add(PresentWaitSemaphore);
// }

void CVulkanWindow::Submit()
{
    if(SecondaryCommandBuffers.Empty())
    {
        bNeedWaitFormerFrame=false;
        return;
    }

    TVector<vk::CommandBuffer> CommandBuffers;
    CommandBuffers.Reserve(
        SecondaryCommandBuffers.SceneCommandBuffers.Num()
        +SecondaryCommandBuffers.ForegroundCommandBuffers.Num()
        +2);
    
    CommandBuffers.Add(ClearImageBuffer);
    CommandBuffers.Append(SecondaryCommandBuffers.SceneCommandBuffers);
    CommandBuffers.Append(SecondaryCommandBuffers.ForegroundCommandBuffers);
    CommandBuffers.Add(PrimaryCommandBuffer);

    vk::PipelineStageFlags WaitStages[]={
        vk::PipelineStageFlagBits::eColorAttachmentOutput
    };

    vk::SubmitInfo SubmitInfo=vk::SubmitInfo()
        .setWaitSemaphoreCount(1)
        .setPWaitSemaphores(&ImageAvailableSemaphore)
        .setPWaitDstStageMask(WaitStages)
        .setCommandBuffers(CommandBuffers)
        .setSignalSemaphoreCount(1)
        .setPSignalSemaphores(&PresentWaitSemaphore);

    CVulkanContext::Get()->GetGraphicQueue().submit(SubmitInfo,RenderFence);

    bNeedWaitFormerFrame=true;
}

void CVulkanWindow::PresentFrame()
{
    if(SecondaryCommandBuffers.Empty())
    {
        return;
    }

    TVector<vk::Semaphore> WaitSemaphores={
        PresentWaitSemaphore
    };

    vk::PresentInfoKHR PresentInfo=vk::PresentInfoKHR()
        .setWaitSemaphores(WaitSemaphores)
        .setSwapchainCount(1)
        .setPSwapchains(&VKSwapChain)
        .setPImageIndices(&CurrentFrame);


    VkPresentInfoKHR PresentInfo2(PresentInfo);

    vk::Result PresentResult= (vk::Result)vkQueuePresentKHR(
        CVulkanContext::Get()->GetPresentQueue(),&PresentInfo2);

    
    if(PresentResult ==vk::Result::eErrorOutOfDateKHR 
        || PresentResult==vk::Result::eSuboptimalKHR)
    {
        bNeedRebuildSwapChain=true;
    }
    else
    {
        assert(PresentResult==vk::Result::eSuccess);
    }

    bNeedRequireImage=true;
}

